Part3 - 6장. 벤치마킹과 튜닝
a++와 ++a는 어느 쪽이 빠를까?
학부 시절 이 주제로 많이 고민했고, 글마다 결론이 달랐다.
결국 중요한 차이가 없다는 것을 알게 됐다.
미시적인 차이를 따지기보다 전체 서비스에 어떤 영향을 줄지 보는 것이 현실적이다.
6.1 벤치마킹
성능 측정을 위해 흔히 사용하는 코드:
var start = (new Date()).getTime();
// TODO: 테스트할 작업
var end = (new Date()).getTime();
console.log(end - start);
하지만 이 방식에는 문제점이 많다:
- 밀리초 이하 단위 측정 불가
- 단일 실행으로 의미 있는 평균 도출 불가
- 부가 작업 간섭
- 환경 의존성
6.1.1 반복
- 반복해도 이상값이 평균을 왜곡할 수 있음
- 타이머 정확도에 의존
- 샘플 수 설정 문제
- 균형 잡힌 비교가 어려움
→ 벤치마킹은 깊은 전문 영역이며, 검증된 라이브러리를 사용하는 것이 좋다.
6.1.2 Benchmark.js
- 통계적으로 검증된 벤치마킹 도구
- 브라우저 외 환경에서도 사용 가능
- 회귀 테스트에도 활용
6.2 콘텍스트가 먼저다
- a++ vs ++a 성능차이는 무의미한 경우가 대부분
- 100나노초 차이라면 실서비스엔 큰 영향 없음
- 미세한 최적화보다는 전체 흐름과 병목에 집중하는 것이 현실적
- 컴퓨터사이언스적으로 의미 있지만, 엔지니어링에선 비효율일 수 있음
6.2.1 엔진 최적화는 예측 불가
var twelve = "12";
var foo = "foo";
var x1 = parseInt(twelve);
var x2 = parseInt(foo);
var y1 = Number(twelve);
var y2 = Number(foo);
- 어떤 방식이 빠른지는 엔진의 구현/최적화 방식에 따라 다름
- 실제 코드로 결과를 확인해야지, 추론만으로 판단하지 말 것
6.3 jsPerf.com
- Benchmark.js 기반 벤치마크 도구
- 웹에서 손쉽게 다양한 테스트 시나리오 비교 가능
- 통계적으로 신뢰도 높은 결과 제공
6.4 좋은 테스트 작성법
- 테스트 케이스 간 의도된 차이점을 명확히 문서화
- 영향 없는 요소는 별도 설정 블록으로 분리
- 실행 속도보다 의미 있는 차이의 맥락을 측정할 것
6.5 미시 성능
6.5.1 엔진마다 다르다
- 자바스크립트 명세는 성능을 보장하지 않는다
- 최적화 대상은 엔진의 내부 휴리스틱에 따름
- 모든 브라우저에 동일 최적화 적용은 불가능
자주 언급되는 최적화 팁:
- 함수 간
arguments전달 피하기 (메모리 누수 유발 가능성) try-catch구문은 함수 외부로 분리 (함수 최적화 저해)
6.5.2 큰 그림
- 임계 경로 코드인지 판단 후 최적화 여부 결정
- 비임계 경로 성능에 집착하는 것은 유지보수에 해로울 수 있음
6.6 꼬리 호출 최적화 (TCO)
ES6 이후 도입된 최적화 개념
function foo(x) { ... }
function bar(y) {
return foo(y + 1); // TCO 가능
}
function baz() {
return 1 + bar(40); // TCO 불가
}
- TCO 지원 엔진은 새 스택 프레임 없이 이전 프레임 재사용
- 특히 재귀 구조에서 효과적
- 속도 향상, 메모리 사용 절감 가능